package com.atguigu.hbase;

import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;

import java.io.IOException;

/**
 * Created by Smexy on 2022/12/7
 *
 *   是否支持JDBC
 *          支持：  JDBC套路
 *                      ck,mysql
 *          不支持:  其他套路
 *                      redis,hbase
 *
 *   原理： hbase不管是什么客户端，在连接服务端时，都需要连接zk
 *
 *   其他套路：
 *          ①创建一个客户端
 *          ②准备命令
 *          ③用客户端发送命令
 *          ④读操作，返回结果。解析结果
 *          ⑤关闭客户端链接
 *
 *  --------------------------
 *      Connection: 创建一个Connection，自动维持连接Server和ZK的连接。
 *                  通过ConnectionFactory创建。
 *                   谁创建，谁关闭(close())
 *                   创建是重量级(费时，费资源)，线程安全(可以在多个线程共享)，建议只在一个App中创建1次。
 *
 *      从Connection中可以获取Table,Admin。
 *              Table:  表对象。代表一张表  负责执行 DML(CRUD)
 *              Admin:  管理员。负责对表进行管理。 负责执行DDL(建表，改表，删表)
 *              一个Connection中获得的Table和Admin可以共享Connection所连接的资源，例如连接服务端，连zk，维护元数据缓存。
 *
 *              Table和Admin的创建是轻量级的(省事，省时，省资源)，建议每个线程都有自己的Table和Admin对象，不要池化或缓存共享。
 *
 *    ----------------------------------
 *      对哪张表操作，需要实例化一个Table对象
 *          插入和修改:  Table.put(Put a)
 *                              Put： 代表向一行执行Put操作。
 *          删除:       Table.delete(Delete a)
 *          查单行:      Table.get(Get a)
 *          查多行:      Table.getScanner(Scan a)
 *
 *       hbase是没有数据类型的，所有的数据都是以byte[]形式存储。
 *        Bytes
 *          写：  把你的数据类型转为 byte[]
 *                      Bytes.toBytes(T t)
 *          读：  把byte[]转为自己的数据类型
 *                      Bytes.toXxx(byte[] x)
 *
 *        CellUtil: 获取Cell中的属性
 *          获取什么属性，调用CellUtil.cloneXxx();
 *              获取rowkey: byte [] x = CellUtil.cloneRowKey();
 */
public class HBaseUtil
{

    //提供方法遍历Result，打印输出
    public static void parseResult(Result result){

        //返回这行所有的cell
        Cell[] cells = result.rawCells();

        for (Cell cell : cells) {

            System.out.println("rk:" + Bytes.toString(CellUtil.cloneRow(cell)) + ",列:" +
                Bytes.toString(CellUtil.cloneFamily(cell)) + ":" +
                Bytes.toString(CellUtil.cloneQualifier(cell)) + ",值:" +
                Bytes.toString(CellUtil.cloneValue(cell)) + ",ts:" + cell.getTimestamp());

        }

    }

    //提供一个目标表的Table对象
    public static Table getTable(String name) throws IOException {

        if (StringUtils.isBlank(name)){
            throw new RuntimeException("表名错误!");
        }

        Table table = conn.getTable(TableName.valueOf(name));

        return table;

    }

    //提供方法，方便封装put.  put '表名','rowkey','列族名:列名',列值
    public static Put createPut(String rk,String cf,String cq,String value){

        Put put = new Put(Bytes.toBytes(rk))
            .addColumn(Bytes.toBytes(cf), Bytes.toBytes(cq), Bytes.toBytes(value));

        return put;

    }

    //静态属性，一般在静态代码块赋值
    // 静态代码块随着类的加载而运行，类只加载一次，静态代码块只运行一次
        private static Connection conn ;

        static {

            // HBaseConfiguration.create(): 读取hadoop的配置文件和hbase的配置文件(默认+自定义)
            try {
                conn = ConnectionFactory.createConnection();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public static void closeConn() throws IOException {
            if (conn != null){
                conn.close();
            }
        }

}
